/*
 * \brief  Root interface to timer service
 * \author Norman Feske
 * \date   2006-08-15
 */

/*
 * Copyright (C) 2006-2009 Norman Feske
 * Genode Labs, Feske & Helmuth Systementwicklung GbR
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

#ifndef _TIMER_ROOT_H_
#define _TIMER_ROOT_H_

#include <util/arg_string.h>
#include <base/printf.h>
#include <base/heap.h>
#include <root/server.h>
#include <cap_session/cap_session.h>

#include "timer_session_component.h"


namespace Timer {

	/*
	 * We do not use the Root_component template from base/root/component.h
	 * because we use a dedicated server activation and entry point for each
	 * timer session whereas the Root_component template uses one and the same
	 * entry point for all sessions.
	 */
	class Root_component : public Genode::Root_server
	{
		private:

			/*
			 * Allocator for allocating timer session
			 * component objects.
			 */
			Genode::Allocator   *_md_alloc;
			Genode::Cap_session *_cap_session;

			/*
			 * We keep the information about all our sessions
			 * in a list to retrieve them for closing.
			 */
			Genode::List<Session_component> _sessions;

		public:

			/**
			 * Constructor
			 */
			Root_component(Genode::Allocator *md_alloc,
			               Genode::Cap_session *cap_session):
				_md_alloc(md_alloc), _cap_session(cap_session) { }


			/********************
			 ** Root interface **
			 ********************/

			Genode::Session_capability session(const char *args)
			{
				Genode::size_t ram_quota = Genode::Arg_string::find_arg(args, "ram_quota").ulong_value(0);

				if (ram_quota < sizeof(Session_component)) {
					PWRN("Insufficient donated ram_quota (%zd bytes), require %zd bytes",
					     ram_quota, sizeof(Session_component));
				}

				Session_component *sc = new (_md_alloc) Session_component(_cap_session);

				_sessions.insert(sc);

				return sc->session();
			}

			void close(Genode::Session_capability session)
			{
				/* find the corresponding component by iterating session list */
				Session_component *sc = _sessions.first();

				for ( ; sc; sc = sc->next())
					if (sc->session().local_name() == session.local_name())
						break;

				if (!sc) {
					PWRN("Cannot retrieve session for closing");
					return;
				}

				_sessions.remove(sc);

				destroy(_md_alloc, sc);
			}
	};
}

#endif
